package com.tyy.springppt.util;

import org.apache.poi.hslf.usermodel.HSLFSlide;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class PPTToImageConverter {

    public static void convertPPTToImagesConcurrently(String pptFilePath, String outputDirectory) throws IOException, InterruptedException, ExecutionException {
        File pptFile = new File(pptFilePath);
        File outputDir = new File(outputDirectory);
        if (!outputDir.exists()) {
            outputDir.mkdirs();
        }

        List<Callable<Boolean>> tasks = new ArrayList<>();
        if (pptFilePath.endsWith(".ppt")) {
            try (FileInputStream fis = new FileInputStream(pptFile);
                 HSLFSlideShow ppt = new HSLFSlideShow(fis)) {
                Dimension pgsize = ppt.getPageSize();
                List<HSLFSlide> slides = ppt.getSlides();
                for (int i = 0; i < slides.size(); i++) {
                    final int slideIndex = i;
                    tasks.add(() -> {
                        BufferedImage img = new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_RGB);
                        Graphics2D graphics = img.createGraphics();
                        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                        graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                        graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
                        graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                        graphics.setColor(Color.white);
                        graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
                        slides.get(slideIndex).draw(graphics);
                        File outputFile = new File(outputDir, "slide_" + (slideIndex + 1) + ".png");
                        return ImageIO.write(img, "png", outputFile);
                    });
                }
            }
        } else if (pptFilePath.endsWith(".pptx")) {
            try (FileInputStream fis = new FileInputStream(pptFile);
                 XMLSlideShow ppt = new XMLSlideShow(fis)) {
                Dimension pgsize = ppt.getPageSize();
                List<XSLFSlide> slides = ppt.getSlides();
                for (int i = 0; i < slides.size(); i++) {
                    final int slideIndex = i;
                    tasks.add(() -> {
                        BufferedImage img = new BufferedImage(pgsize.width, pgsize.height, BufferedImage.TYPE_INT_RGB);
                        Graphics2D graphics = img.createGraphics();
                        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                        graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                        graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
                        graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                        graphics.setColor(Color.white);
                        graphics.fill(new Rectangle2D.Float(0, 0, pgsize.width, pgsize.height));
                        slides.get(slideIndex).draw(graphics);
                        File outputFile = new File(outputDir, "slide_" + (slideIndex + 1) + ".png");
                        return ImageIO.write(img, "png", outputFile);
                    });
                }
            }
        }

        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        // 执行任务
        List<Future<Boolean>> futures = executorService.invokeAll(tasks);

        // 收集转换失败的任务
        List<Callable<Boolean>> failedTasks = new ArrayList<>();
        for (int i = 0; i < futures.size(); i++) {
            Future<Boolean> future = futures.get(i);
            if (!future.get()) {
                failedTasks.add(tasks.get(i));
            }
        }

        // 对失败的任务进行重试
        if (!failedTasks.isEmpty()) {
            System.out.println("有 " + failedTasks.size() + " 个任务转换失败，开始重试...");
            List<Future<Boolean>> retryFutures = executorService.invokeAll(failedTasks);
            for (Future<Boolean> retryFuture : retryFutures) {
                if (!retryFuture.get()) {
                    System.out.println("重试后仍有任务转换失败");
                }
            }
        }

        // 关闭线程池
        executorService.shutdown();
    }

    public static void main(String[] args) {
        String pptFilePath = "path/to/your/ppt/file.pptx";
        String outputDirectory = "path/to/output/directory";
        try {
            convertPPTToImagesConcurrently(pptFilePath, outputDirectory);
            System.out.println("转换完成");
        } catch (IOException | InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}